<div class="standardContainer">
    <div class="ui basic segment">
        <h2>HTTP Proxy</h2>
        <p>Proxy HTTP server with HTTP or HTTPS for multiple hosts. If you are only proxying for one host / domain, use Default Site instead.</p>
    </div>
    <style>
        #httpProxyList .ui.toggle.checkbox input:checked ~ label::before{
            background-color: #00ca52 !important;
        }

        .subdEntry td:not(.ignoremw){
            min-width: 100px;
        }

        .httpProxyListTools{
            width: 100%;
        }

        .tag-select{
            cursor: pointer;
        }

        th.no-sort{
            cursor: default !important;
        }

        .tag-select:hover{
            text-decoration: underline;
            opacity: 0.8;
        }

        .inlineEditActionBtn{
            border: 0px solid transparent !important;
            box-shadow: none !important;
            background-color: transparent !important;
        }

        body.darkTheme .ui.basic.small.icon.circular.button.inlineEditActionBtn{
            border: 0px solid transparent !important;
        }

        /* Custom, non overlaying modal for proxy rule editing */
        #httprpEditModal{
            position: fixed;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            width: 68vw;
            height: 75vh;
            background-color: var(--theme_bg_primary);
            padding: 1.4em;
            border-radius: .6em;
            box-shadow: 0px 4px 8px rgba(0, 0, 0, 0.2), 0px 8px 16px rgba(0, 0, 0, 0.2);
            z-index: 8;
            max-width: 840px;
        }

        #httprpEditModal .rpconfig_content{
            height: 100%;
        }

        #httprpEditModal .editor_side_wrapper{
            position: absolute;
            top: 0;
            right: 0;
            height:100%;
            width: 100%;
            background-color: var(--theme_bg_primary);
        }

        #httprpEditModal .wrapper_frame{
            width: 100%;
            border: 1px solid var(--divider_color);
            border-radius: 0.5em;
            height: calc(100%);
        }

        #httprpEditModal .editor_side_wrapper .wrapper_frame{
            height: calc(100% - 30px);
        }

        #httprpEditModal .editor_back_button {
            border: none;
            background-color: transparent;
            box-shadow: none;
            color: var(--text_color);
            font-size: 2.2em;
            cursor: pointer;
            padding-top: 20px;
        }

        #httprpEditModal .editor_back_button:hover{
            opacity: 0.5;
        }

        @media screen and (max-width: 1024px) {
            #httprpEditModal {
                width: 85vw;
            }
        }

        @media screen and (max-width: 768px) {
            #httprpEditModal {
                height: 80vh;
                border-radius: 0;
                overflow-y: scroll;
                overflow-x: hidden;
                width: 100%;
            }

            /* Override the ui grid */
            #httprpEditModalSideMenu{
                width: 16% !important;
            }

            #httprpEditModalContentWindow{
                width: 84% !important;
            }

            #httprpEditModal{
                padding-left: 0;
                padding-right: 0;
            }

            .editorSideMenuText{
                display:none;
            }

            .hrpedit_menu_item{
                height: 2.4em;
            }
            
            .httpProxyEditClosePC{
                display:none !important;
            }
            .httpProxyEditCloseMobile{
                display:block !important;
                position: absolute;
                left: 1.25em !important;
                bottom: 1em;
            }
        }

        @media screen and (min-width: 769px) {
            .httpProxyEditClosePC{
                display:block !important;
            }
            .httpProxyEditCloseMobile{
                display:none !important;
            }
        }

        #httprpEditDarkenLayer {
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background-color: rgba(0, 0, 0, 0.5);
            z-index: 7;
            backdrop-filter: blur(3px);
        }

        #httprpEditModalWrapper {
            display: none; /* Hidden by default */
        }
    </style>
    <div class="httpProxyListTools" style="margin-bottom: 1em;">
        <div id="tagFilterDropdown" class="ui floating basic dropdown labeled icon button" style="min-width: 150px;">
            <i class="filter icon"></i>
            <span class="text">Filter by tags</span>
            <div class="menu">
              <div class="ui icon search input">
                <i class="search icon"></i>
                <input type="text" placeholder="Search tags...">
              </div>
              <div class="divider"></div>
                <div class="scrolling menu tagList">
                    <!--
                    Example: 
                    <div class="item">
                        <div class="ui red empty circular label"></div>
                        Important
                    </div>
                    -->
                    <!-- Add more tag options dynamically -->
                </div>
            </div>
        </div>
        <div class="ui small input"  style="width: 300px; height: 38px;">
            <!-- Prevent the browser from filling the saved Zoraxy login account into the  input searchInput below -->
            <input type="password"  autocomplete="off" hidden/>
            <input type="text" id="searchInput"  placeholder="Quick Search" onkeydown="handleSearchInput(event);" onchange="handleSearchInput(event);" onblur="handleSearchInput(event);">
        </div>
    </div>
    
    <div style="width: 100%; overflow-x: auto; margin-bottom: 1em; min-height: 300px;">
        <table class="ui unstackable sortable compact celled definition table">
            <thead>
                <tr>
                    <th></th>
                    <th>Host</th>
                    <th>Destination</th>
                    <th>Virtual Directory</th>
                    <th class="no-sort">Tags</th>
                    <th class="no-sort" style="width:100px; cursor: default !important;"></th>
                </tr>
            </thead>
            <tbody id="httpProxyList">
            
            </tbody>
        </table>
    </div>

    <button class="ui icon right floated basic button" onclick="listProxyEndpoints();"><i class="green refresh icon"></i> Refresh</button>
    <br><br>
</div>

<!-- Modal for editing a HTTP Proxy Rule -->
<div id="httprpEditModalWrapper">
    <div id="httprpEditModal" editing-host="">
        <div class="ui grid" style="height:100%;">
            <div id="httprpEditModalSideMenu" class="four wide column">
                <div class="ui secondary fluid vertical menu">
                    <a class="active item hrpedit_menu_item" cfgpage="downstream">
                        <i class="home icon"></i> <span class="editorSideMenuText">Host</span>
                    </a>
                    <a class="item hrpedit_menu_item" cfgpage="upstream">
                        <i class="server icon"></i> <span class="editorSideMenuText">Destinations</span>
                    </a>
                    <a class="item hrpedit_menu_item" cfgpage="vdirs">
                        <i class="angle folder icon"></i> <span class="editorSideMenuText">Virtual Directory</span>
                    </a>
                    <a class="item hrpedit_menu_item" cfgpage="alias">
                        <i class="at icon"></i> <span class="editorSideMenuText">Alias</span>
                    </a>
                    <a class="item hrpedit_menu_item" cfgpage="ssl">
                        <i class="lock icon"></i> <span class="editorSideMenuText">TLS / SSL</span>
                    </a>
                    <a class="item hrpedit_menu_item" cfgpage="headers">
                        <i class="heading icon"></i> <span class="editorSideMenuText">Headers</span>
                    </a>
                    <a class="item hrpedit_menu_item" cfgpage="accessrule">
                        <i class="star icon"></i> <span class="editorSideMenuText">Access Rules</span>
                    </a>
                    <a class="item hrpedit_menu_item" cfgpage="security">
                        <i class="key icon"></i> <span class="editorSideMenuText">Security</span>
                    </a>
                    <a class="item hrpedit_menu_item" cfgpage="tags">
                        <i class="tags icon"></i> <span class="editorSideMenuText">Tags</span>
                    </a>
                </div>

                <button class="ui basic fluid button httpProxyEditClosePC" onclick="closeHttpRuleEditor();">Close</button>
                <button class="ui basic icon circular button httpProxyEditCloseMobile"  onclick="closeHttpRuleEditor();"><i class="ui times icon"></i></button>
            </div>
            <div id="httprpEditModalContentWindow" class="twelve wide column">
                <div style="height:100%;">
                    <!-- Host -->
                    <div class="rpconfig_content" rpcfg="downstream">
                        <div class="ui segment">
                            <h3>
                                <button class="ui right floated small icon circular basic button downstream_primary_hostname_edit_btn">
                                    <i class="ui edit icon"></i>
                                </button>
                                <span class="downstream_primary_hostname"></span>
                            </h3>
                            <div class="ui action small fluid input downstream_primary_hostname_edit_input" style="margin-bottom: 0.4em;">
                                <input type="text" placeholder="new.example.com">
                                <button class="ui green basic icon button saveDownstreamHostnameBtn">
                                    <i class="ui save icon"></i>
                                </button>
                                <button class="ui basic icon button cancelDownstreamHostnameBtn">
                                    <i class="times icon"></i>
                                </button>
                            </div>
                            <div class="downstream_alias_hostname">

                            </div>
                            <div class="ui divider"></div>
                            <div class="downstream_action_list">
                                <div class="ui checkbox" style="margin-top: 0.4em;">
                                    <input type="checkbox" class="BypassGlobalTLS">
                                    <label>Allow plain HTTP access<br>
                                        <small>Allow inbound connections without TLS/SSL</small></label>
                                </div>
                                <br>
                                <div class="ui checkbox" style="margin-top: 0.4em;">
                                    <input type="checkbox" class="DisableLogging">
                                    <label>Disable Requests Logging<br>
                                        <small>Disable logging for all incoming requests for this hostname</small></label>
                                </div>
                                <br>
                                <div class="ui checkbox" style="margin-top: 0.4em;">
                                    <input type="checkbox" class="DisableStatisticCollection">
                                    <label>Disable Statistic Collection<br>
                                        <small>Disable collecting statistics for this hostname but keep request logging</small></label>
                                </div>
                                <br>
                            </div>
                           
                        </div>
                    </div>
                    <!-- Destinations -->
                    <div class="rpconfig_content" rpcfg="upstream">
                        <div class="ui segment">
                            <b>Enabled Upstreams</b>
                            <div class="upstream_list" style="margin-top: 0.4em;">

                            </div>
                            <button class="ui basic compact button editUpstreamButton" style="margin-left: 0.4em; margin-top: 1em;"><i class="grey server icon"></i> Edit Upstreams</button>
                            <div class="ui divider"></div>
                            <div class="ui checkbox" style="margin-top: 0.4em;">
                                <input type="checkbox" class="EnableUptimeMonitor">
                                <label>Monitor Uptime<br>
                                    <small>Enable active uptime monitor and auto disable upstreams that are offline</small></label>
                            </div>
                            <br>
                            <!-- <div class="ui checkbox" style="margin-top: 0.4em; margin-left: 2em;">
                                <input type="checkbox" class="DisableAutoFallback">
                                <label>Disable Auto Fallback<br>
                                    <small>Continue monitoring but don't automatically disable upstreams when offline</small></label>
                            </div>
                            <br> -->
                            <div class="ui checkbox" style="margin-top: 0.4em;">
                                <input type="checkbox" class="UseStickySession">
                                <label>Use Sticky Session<br>
                                    <small>Enable stick session on load balancing</small></label>
                            </div>
                            <br>
                            <div class="ui checkbox" style="margin-top: 0.4em;">
                                <input type="checkbox" class="DisableChunkedTransferEncoding">
                                <label>Disable Chunked Transfer Encoding<br>
                                    <small>Enable this option if your upstream uses a legacy HTTP server implementation (e.g. Proxmox / opencloud)</small></label>
                            </div>    
                        </div>
                    </div>
                    <!-- Virtual Directories-->
                    <div class="rpconfig_content" rpcfg="vdirs">
                        <div class="ui segment">
                            <b>List of Virtual Directories</b>
                            <div class="vdir_list" style="margin-top:0.4em;">

                            </div>
                            <div class="ui divider"></div>
                            <button class="ui basic tiny button editVdirBtn" style="margin-left: 0.4em; margin-top: 0.4em;">
                                <i class="ui yellow folder icon"></i> Edit Virtual Directories
                            </button>
                        </div>
                    </div>
                    <!-- Alias -->
                    <div class="rpconfig_content" rpcfg="alias">
                        <iframe src="" class="wrapper_frame">

                        </iframe>
                    </div>
                    <!-- TLS / SSL -->
                    <div class="rpconfig_content" rpcfg="ssl">
                        <div class="ui segment">
                            <p>The table below shows which certificate will be served by Zoraxy when a client request the following hostnames.</p>
                            <div class="ui blue message sni_grey_out_info" style="margin-bottom: 1em; display:none;">
                                <i class="info circle icon"></i>
                                Certificate dropdowns are greyed out because SNI is enabled
                            </div>
                            <table class="ui celled small compact table sortable Tls_resolve_list">
                                <thead>
                                    <tr>
                                        <th>Hostname</th>
                                        <th class="no-sort">Resolve to Certificate</th>
                                    </tr>
                                </thead>
                                <tbody>
                                    <!-- Rows will be dynamically populated -->
                                </tbody>
                            </table>
                            <div class="ui checkbox" style="margin-top: 0.4em;">
                                <input type="checkbox" class="Tls_EnableSNI">
                                <label>Enable SNI<br>
                                    <small>Resolve Server Name Indication (SNI) and automatically select a certificate</small>
                                </label>
                            </div>
                            <div class="ui checkbox" style="margin-top: 0.4em;">
                                <input type="checkbox" class="Tls_EnableLegacyCertificateMatching">
                                <label>Enable Legacy Certificate Matching<br>
                                    <small>Use filename for hostname matching, faster but less accurate</small>
                                </label>
                            </div>
                            <div class="ui disabled checkbox" style="margin-top: 0.4em;">
                                <input type="checkbox" class="Tls_EnableAutoHTTPS">
                                <label>Enable Auto HTTPS (WIP)<br>
                                    <small>Automatically request a certificate for the domain</small>
                                </label>
                            </div>
                            
                            <br>
                            <div class="ui divider"></div>
                            <button class="ui basic small button getCertificateBtn" style="margin-left: 0.4em; margin-top: 0.4em;"><i class="green lock icon"></i> Get Certificate</button>
                            <button class="ui basic small button getSelfSignCertBtn" style="margin-left: 0.4em; margin-top: 0.4em;"><i class="yellow lock icon"></i> Generate Self-Signed Certificate</button>
                        </div>
                    </div>
                    <!-- Custom Headers -->
                    <div class="rpconfig_content" rpcfg="headers">
                        <iframe src="" class="wrapper_frame">

                        </iframe>
                    </div>
                    <!-- Access Rule -->
                    <div class="rpconfig_content" rpcfg="accessrule">
                        <iframe src="" class="wrapper_frame">

                        </iframe>
                    </div>
                    <!-- Security -->
                    <div class="rpconfig_content" rpcfg="security">
                        <div class="ui segment">
                            <div class="grouped fields authProviderPicker">
                                <!-- Auth Providers -->
                                <label><b>Authentication Provider</b></label>
                                <div class="field">
                                    <div class="ui radio checkbox">
                                        <input type="radio" value="0" name="authProviderType">
                                        <label>None (Anyone can access)</label>
                                    </div>
                                </div>
                                <div class="field">
                                    <div class="ui radio checkbox">
                                        <input type="radio" value="1" name="authProviderType">
                                        <label>Basic Auth</label>
                                    </div>
                                </div>
                                <div class="field">
                                    <div class="ui radio checkbox">
                                        <input type="radio" value="2" name="authProviderType">
                                        <label>Forward Auth</label>
                                    </div>
                                </div>
                                <div class="field">
                                    <div class="ui radio checkbox">
                                        <input type="radio" value="3" name="authProviderType">
                                        <label>OAuth2</label>
                                    </div>
                                </div>
                            </div>
                            <br>
                            <button class="ui basic compact small button editBasicAuthCredentialsBtn" style="margin-left: 0.4em; margin-top: 0.4em;"><i class="ui blue user circle icon"></i> Basic Auth Credentials</button>
                            <div class="ui divider"></div>
                            <!-- Block Common Exploits -->
                            <label><b>Exploits Prevention</b></label>
                            <br>
                            <div class="ui checkbox" style="margin-top: 0.4em;">
                                <input type="checkbox" class="BlockCommonExploits">
                                <label>Block Common Exploits (Experimental)<br>
                                    <small>Detect and block common exploit payloads (SQLi, XSS, path traversal, etc.)</small>
                                </label>
                            </div>
                            <br>
                            <div class="ui checkbox" style="margin-top: 0.4em;">
                                <input type="checkbox" class="BlockAICrawlers">
                                <label>Block AI and Crawlers (Experimental)<br>
                                    <small>Block known crawlers and large-scale automated agents</small>
                                </label>
                            </div>
                            <br>
                            <label>Mitigation Action</label>
                            <div class="ui fluid selection dropdown mitigationActionDropdown" style="margin-top: 0.4em;">
                                <input type="hidden" value="0" name="mitigationAction">
                                <i class="dropdown icon"></i>
                                <div class="default text">Choose action when exploit / crawler detected</div>
                                <div class="menu">
                                    <div class="item" data-value="0">404 Not Found</div>
                                    <div class="item" data-value="1">403 Forbidden</div>
                                    <div class="item" data-value="2">400 Bad Request</div>
                                    <div class="item" data-value="3">Drop Connection</div>
                                    <div class="disabled item" data-value="4">Captcha Challenge</div> <!-- Work in progress -->
                                </div>
                            </div>
                             <small style="opacity:0.7;">Select how the system should respond when malicious or automated traffic is detected.</small>
                            <div class="ui divider"></div>
                            <!-- Rate Limits-->
                            <div class="ui checkbox" style="margin-top: 0.4em;">
                                <input type="checkbox" onchange="handleToggleRateLimitInput();" class="RequireRateLimit" ${rateLimitCheckState}>
                                <label>Require Rate Limit<br>
                                <small>Check this to enable rate limit on this inbound hostname</small></label>
                            </div><br>
                            <div class="ui small right labeled fluid input" style="margin-top: 0.4em;">
                                <input type="number" class="RateLimit" value="0" min="1" >
                                <label class="ui basic label">
                                    req / sec / IP
                                </label>
                            </div>
                        </div>
                    </div>
                    <!-- Tags -->
                    <div class="rpconfig_content" rpcfg="tags">
                        <iframe src="" class="wrapper_frame">

                        </iframe>
                    </div>
                </div>
                <!-- Editor Side Wrapper -->
                <div class="editor_side_wrapper" style="display:none;">
                    <a class="editor_back_button">
                        <i class="chevron circle left icon" style="margin-top: 22px;"></i>
                    </a>
                    <iframe src="snippet/placeholder.html" class="wrapper_frame">

                    </iframe>
                </div>
            </div>
        </div>
    </div>
    <div id="httprpEditDarkenLayer"></div>
</div>


<script>
    var httpProxyList = []; //Proxy list of the current node

    $('#httprpEditModal .tabular.menu .item').tab();

    /* Renderers */
    function renderUpstreamList(subd){
        //Build the upstream list
        let upstreams = "";
        if (subd.ActiveOrigins.length == 0){
            //Invalid config
            upstreams = `<i class="ui yellow exclamation triangle icon"></i> No Active Upstream Origin<br>`;
        }else{
            subd.ActiveOrigins.forEach(upstream => {
                //console.log(upstream);
                //Check if the upstreams require TLS connections
                let tlsIcon = "";
                if (upstream.RequireTLS){
                    tlsIcon = `<i class="green lock icon" title="TLS Mode"></i>`;
                    if (upstream.SkipCertValidations){
                        tlsIcon = `<i class="yellow lock icon" title="TLS/SSL mode without verification"></i>`
                    }
                }

                let upstreamLink = `${upstream.RequireTLS?"https://":"http://"}${upstream.OriginIpOrDomain}`;

                upstreams += `<a href="${upstreamLink}" target="_blank">${upstream.OriginIpOrDomain} ${tlsIcon}</a><br>`;
            })
        }
        return upstreams;
    }

    function renderVirtualDirectoryList(subd){
        let vdList = `<div class="ui list">`;
        subd.VirtualDirectories.forEach(vdir => {
            vdList += `<div class="item">${vdir.MatchingPath} <i class="green angle double right icon"></i> ${vdir.Domain}</div>`;
        });
        vdList += `</div>`
        if (subd.VirtualDirectories.length == 0){
            vdList = `<small style="opacity: 0.3; pointer-events: none; user-select: none;">No Virtual Directory</small>`;
        }

        return vdList;
    }

    function renderTagList(subd){
        let tagList = "";
        if (subd.Tags.length > 0){
            tagList = subd.Tags.map(tag => `<span class="ui tiny label tag-select" style="background-color: ${getTagColorByName(tag)}; color: ${getTagTextColor(tag)}">${tag}</span>`).join("");
        }else{
            tagList = "<small style='opacity: 0.3; pointer-events: none; user-select: none;'>No Tags</small>";
            tagListEmpty = true;
        }
        return tagList;
    }

    /* List all proxy endpoints */
    function listProxyEndpoints(){
        $.get("/api/proxy/list?type=host", function(data){
            $("#httpProxyList").html(``);
            if (data.error !== undefined){
                    $("#httpProxyList").append(`<tr>
                    <td data-label="" colspan="5"><i class="remove icon"></i> ${data.error}</td>
                </tr>`);
            }else if (data.length == 0){
                $("#httpProxyList").append(`<tr>
                    <td data-label="" colspan="5"><i class="green check circle icon"></i> No HTTP Proxy Record</td>
                </tr>`);
            }else{
                //Sort by RootOrMatchingDomain field
                data.sort((a,b) => (a.RootOrMatchingDomain > b.RootOrMatchingDomain) ? 1 : ((b.RootOrMatchingDomain > a.RootOrMatchingDomain) ? -1 : 0))
                httpProxyList = data;
                data.forEach(subd => {
                    let subdData = encodeURIComponent(JSON.stringify(subd));
                    
                    //Build the upstream list
                    let upstreams = renderUpstreamList(subd);

                    let inboundTlsIcon = "";
                    if ($("#tls").checkbox("is checked")){
                        inboundTlsIcon = `<i class="green lock icon" title="TLS Mode"></i>`;
                        if (subd.BypassGlobalTLS){
                            inboundTlsIcon = `<i class="grey lock icon" title="TLS Bypass Enabled"></i>`;
                        }
                    }else{
                        inboundTlsIcon = `<i class="yellow lock open icon" title="Plain Text Mode"></i>`;
                    }
                    
                    //Build the virtual directory list
                    let vdList = renderVirtualDirectoryList(subd);
                    let vdIsEmpty = (subd.VirtualDirectories.length == 0);

                    //Build the Subdomain enable checkbox
                    let enableChecked = "checked";
                    if (subd.Disabled){
                        enableChecked = "";
                    }

                    //Generate a  the TLS lock icons
                    let httpProto = "http://";
                    if ($("#tls").checkbox("is checked")) {
                        httpProto = "https://";
                    } else {
                        httpProto = "http://";
                    }
                    let hostnameRedirectPort = currentListeningPort;
                    if (hostnameRedirectPort == 80 || hostnameRedirectPort == 443){
                        hostnameRedirectPort = "";
                    }else{
                        hostnameRedirectPort = ":" + hostnameRedirectPort;
                    }

                    //Generate alias domain list
                    let aliasDomains = ``;
                    if (subd.MatchingDomainAlias != undefined && subd.MatchingDomainAlias.length > 0){
                        aliasDomains = `<small class="aliasDomains" eptuuid="${subd.RootOrMatchingDomain}" style="color: #636363;">Alias: `;
                        subd.MatchingDomainAlias.forEach(alias => {
                            aliasDomains += `<a href="${httpProto}${alias}${hostnameRedirectPort}" target="_blank">${alias}</a>, `;
                        });
                        aliasDomains = aliasDomains.substr(0, aliasDomains.length - 2); //Remove the last tailing seperator
                        aliasDomains += `</small><br>`;
                    }

                    //Build the sorting value
                    let destSortValue = subd.ActiveOrigins.map(o => {
                        // Check if it's an IP address (with optional port)
                        let upstreamAddr = o.OriginIpOrDomain;
                        let subpath = "";
                        if (upstreamAddr.indexOf("/") !== -1) {
                            let parts = upstreamAddr.split("/");
                            subpath = parts.slice(1).join("/");
                            upstreamAddr = parts[0];
                        }
                        let ipPortRegex = /^(\d{1,3}\.){3}\d{1,3}(:\d+)?$/;
                        if (ipPortRegex.test(upstreamAddr)) {
                            let [ip, port] = upstreamAddr.split(":");
                            // Convert IP to hex
                            let hexIp = ip.split('.').map(x => ('00' + parseInt(x).toString(16)).slice(-2)).join('');
                            let hexPort = port ? (port.length < 5 ? port.padStart(5, '0') : port) : '';
                            return hexIp + (hexPort ? ':' + hexPort : '') + "/" + subpath;
                        }
                        // Otherwise, treat it as a domain name
                        return upstreamAddr;
                    }).join(",");
                    
                    //Build tag list
                    let tagList = renderTagList(subd);
                    let tagListEmpty = (subd.Tags.length == 0);
                    
                    $("#httpProxyList").append(`<tr eptuuid="${subd.RootOrMatchingDomain}" payload="${subdData}" class="subdEntry">
                        <td class="collapsing ignoremw" datatype="enable">
                            <div class="ui toggle tiny fitted checkbox" style="margin-bottom: -0.5em; margin-right: 0.4em;" title="Enable / Disable Rule">
                                <input type="checkbox" class="enableToggle" name="active" ${enableChecked} eptuuid="${subd.RootOrMatchingDomain}" onchange="handleProxyRuleToggle(this);">
                                <label></label>
                            </div>
                        </td>
                        <td data-label="" editable="true" datatype="inbound">
                            <a href="${httpProto}${subd.RootOrMatchingDomain}${hostnameRedirectPort}" target="_blank">${subd.RootOrMatchingDomain}</a> ${inboundTlsIcon}<br>
                            ${aliasDomains}
                            <small class="accessRuleNameUnderHost" ruleid="${subd.AccessFilterUUID}"></small>
                        </td>
                        <td data-label="" editable="true" datatype="domain" data-sort-value="${destSortValue}" style="word-break: break-all;">
                            <div class="upstreamList">
                                ${upstreams}        
                            </div>
                        </td>
                        <td data-label="" editable="true" datatype="vdir" style="${vdIsEmpty?"text-align: center;":""}">${vdList}</td>
                        <td data-label="tags" payload="${encodeURIComponent(JSON.stringify(subd.Tags))}" datatype="tags" style="${tagListEmpty?"text-align: center;":""}">
                            <div class="tags-list">
                            ${tagList}
                            </div>
                        </td>
                        <!-- <td data-label="" editable="true" datatype="advanced" style="width: 350px;">
                            ${subd.AuthenticationProvider.AuthMethod == 0x1?`<i class="ui grey key icon"></i> Basic Auth`:``}
                            ${subd.AuthenticationProvider.AuthMethod == 0x2?`<i class="ui blue key icon"></i> Forward Auth`:``}
                            ${subd.AuthenticationProvider.AuthMethod == 0x3?`<i class="ui yellow key icon"></i> OAuth2`:``}
                            ${subd.AuthenticationProvider.AuthMethod != 0x0 && subd.RequireRateLimit?"<br>":""}
                            ${subd.RequireRateLimit?`<i class="ui green check icon"></i> Rate Limit @ ${subd.RateLimit} req/s`:``}
                            ${subd.AuthenticationProvider.AuthMethod == 0x0 && !subd.RequireRateLimit?`<small style="opacity: 0.3; pointer-events: none; user-select: none;">No Special Settings</small>`:""}
                        </td> -->
                        <td class="center aligned ignoremw" editable="true" datatype="action" data-label="">
                            <button title="Edit Proxy Rule" class="ui circular small basic icon button editBtn inlineEditActionBtn" onclick='editEndpoint("${(subd.RootOrMatchingDomain).hexEncode()}")'><i class="ellipsis vertical icon"></i></button>
                            <button title="Remove Proxy Rule" class="ui circular mini red basic icon button inlineEditActionBtn" onclick='deleteEndpoint("${(subd.RootOrMatchingDomain).hexEncode()}")'><i class="trash icon"></i></button>
                        </td>
                    </tr>`);
                });
                populateTagFilterDropdown(data);
            }

            resolveAccessRuleNameOnHostRPlist();
        });
    }

    //Perform realtime alias update without refreshing the whole page
    function updateAliasListForEndpoint(endpointName, newAliasDomainList){
        let targetEle = $(`.aliasDomains[eptuuid='${endpointName}']`);
        console.log(targetEle);
        if (targetEle.length == 0){
            return;
        }

        let aliasDomains = ``;
        if (newAliasDomainList != undefined && newAliasDomainList.length > 0){
            aliasDomains = `Alias: `;
            newAliasDomainList.forEach(alias => {
                aliasDomains += `<a href="//${alias}" target="_blank">${alias}</a>, `;
            });
            aliasDomains = aliasDomains.substr(0, aliasDomains.length - 2); //Remove the last tailing seperator
            $(targetEle).html(aliasDomains);
            $(targetEle).show();
        }else{
            $(targetEle).hide();
        }
    }

    //Resolve & Update all rule names on host PR list
    function resolveAccessRuleNameOnHostRPlist(){
        //Resolve the access filters
        $.get("/api/access/list", function(data){
            console.log(data);
            if (data.error == undefined){
                //Build a map base on the data
                let accessRuleMap = {};
                for (var i = 0; i < data.length; i++){
                    accessRuleMap[data[i].ID] = data[i];
                }
                
                
                $(".accessRuleNameUnderHost").each(function(){
                    let thisAccessRuleID = $(this).attr("ruleid");
                    if (thisAccessRuleID== ""){
                        thisAccessRuleID = "default"
                    }

                    if (thisAccessRuleID == "default"){
                        //No need to label default access rules
                        $(this).html("");
                        return;
                    }

                    let rule = accessRuleMap[thisAccessRuleID];
                    if (rule == undefined){
                        //Missing config or config too old
                        $(this).html(`<i class="ui red exclamation triangle icon"></i> <b style="color: #db2828;">Access Rule Error</b>`);
                        return;
                    }
                    let icon = `<i class="ui grey filter icon"></i>`;
                    if (rule.ID == "default"){
                        icon = `<i class="ui yellow star icon"></i>`;
                    }else if (rule.BlacklistEnabled && !rule.WhitelistEnabled){
                        //This is a blacklist filter
                        icon = `<i class="ui red filter icon"></i>`;
                    }else if (rule.WhitelistEnabled && !rule.BlacklistEnabled){
                        //This is a whitelist filter
                        icon = `<i class="ui green filter icon"></i>`;
                    }else if (rule.WhitelistEnabled && rule.BlacklistEnabled){
                        //Whitelist and blacklist filter
                        icon = `<i class="ui yellow filter icon"></i>`;
                    }

                    if (rule != undefined){
                        $(this).html(`${icon} ${rule.Name}`);
                    }
                });
            }
        })
    }

    //Update the access rule name on given epuuid, call by hostAccessEditor.html
    function updateAccessRuleNameUnderHost(epuuid, newruleUID){
        $(`tr[eptuuid='${epuuid}'].subdEntry`).find(".accessRuleNameUnderHost").attr("ruleid", newruleUID);
        resolveAccessRuleNameOnHostRPlist();
    }

    
    /*
        Inline editor for httprp.html
    */

    function editEndpoint(uuid) {
        uuid = uuid.hexDecode();
        var row = $('tr[eptuuid="' + uuid + '"]');
        var payload = $(row).attr("payload");
        payload = JSON.parse(decodeURIComponent(payload));
        //Show the HTTP Proxy Rule Editor Modal
        initHttpProxyRuleEditorModal(payload);
        return;
    }

    //handleToggleRateLimitInput will get trigger if the "require rate limit" checkbox
    // is changed and toggle the disable state of the rate limit input field
    function handleToggleRateLimitInput(){
        let isRateLimitEnabled = $("#httpProxyList input.RequireRateLimit")[0].checked;
        if (isRateLimitEnabled){
            $("#httpProxyList input.RateLimit").parent().removeClass("disabled");
        }else{
            $("#httpProxyList input.RateLimit").parent().addClass("disabled");
        }
    }

    function exitProxyInlineEdit(){
        listProxyEndpoints();
        $("#httpProxyList").find(".editBtn").removeClass("disabled");
    }

    function saveTlsConfigs(uuid){
        let enableSNI = $("#httprpEditModal .Tls_EnableSNI")[0].checked;
        let enableLegacyCertificateMatching = $("#httprpEditModal .Tls_EnableLegacyCertificateMatching")[0].checked;
        let enableAutoHTTPS = $("#httprpEditModal .Tls_EnableAutoHTTPS")[0].checked;
        let newTlsOption = {
            "DisableSNI": !enableSNI,
            "DisableLegacyCertificateMatching": !enableLegacyCertificateMatching,
            "EnableAutoHTTPS": enableAutoHTTPS,
        }
        $.cjax({
            url: "/api/proxy/setTlsConfig",
            method: "POST",
            data: {
                "ep": uuid,
                "tlsConfig": JSON.stringify(newTlsOption)
            },
            success: function(data){
                if (data.error !== undefined){
                    msgbox(data.error, false, 3000);
                }else{
                    msgbox("TLS Config updated");
                }
                updateTlsResolveList(uuid);
            }
        });
    }

    function updateTlsResolveList(uuid){
        let editor = $("#httprpEditModalWrapper");
        editor.find(".certificateDropdown .ui.dropdown").off("change");
        editor.find(".certificateDropdown .ui.dropdown").remove();

        //Update the TLS resolve list
        $.ajax({
            url: "/api/cert/resolve?domain=" + uuid,
            method: "GET",
            success: function(data) {
                // Populate the TLS resolve list
                let resolveList = editor.find(".Tls_resolve_list tbody");
                resolveList.empty(); // Clear existing entries
                let primaryDomain = data.domain;
                let aliasDomains = data.alias_domains || [];
                let certMap = data.domain_key_pair;

                // Add primary domain entry
                resolveList.append(`
                    <tr>
                        <td>${primaryDomain}</td>
                        <td class="certificateDropdown" domain="${primaryDomain}">${certMap[primaryDomain] || "Fallback Certificate"}</td>
                    </tr>
                `);
                aliasDomains.forEach(alias => {
                    resolveList.append(`
                        <tr>
                            <td>${alias}</td>
                            <td class="certificateDropdown" domain="${alias}">${certMap[alias] || "Fallback Certificate"}</td>
                        </tr>
                    `);
                });

                //Generate the certificate dropdown
                generateCertificateDropdown(function(dropdown) {
                    let SNIEnabled = editor.find(".Tls_EnableSNI")[0].checked;
                    editor.find(".certificateDropdown").html(dropdown);
                    editor.find(".certificateDropdown").each(function() {
                        let dropdownDomain = $(this).attr("domain");
                        let selectedCertname = certMap[dropdownDomain];
                        if (selectedCertname) {
                            $(this).find(".ui.dropdown").dropdown("set selected", selectedCertname);
                        }
                    });

                    editor.find(".certificateDropdown .ui.dropdown").dropdown({
                        onChange: function(value, text, $selectedItem) {
                            console.log("Selected certificate for domain:", $(this).parent().attr("domain"), "Value:", value);
                            let domain = $(this).parent().attr("domain");
                            let newCertificateName = value;
                            $.cjax({
                                url: "/api/cert/setPreferredCertificate",
                                method: "POST",
                                data: {
                                    "domain": domain,
                                    "certname": newCertificateName
                                },
                                success: function(data) {
                                    if (data.error !== undefined) {
                                        msgbox(data.error, false, 3000);
                                    } else {
                                        msgbox("Preferred Certificate updated");
                                    }
                                }
                            });
                        }
                    });
                    
                    if (SNIEnabled) {
                        editor.find(".certificateDropdown .ui.dropdown").addClass("disabled");
                        editor.find(".sni_grey_out_info").show();
                    }else{
                        editor.find(".sni_grey_out_info").hide();
                    }
                });
            }
        });
    }

    function saveProxyInlineEdit(uuid){
        let editor = $("#httprpEditModal");
        
        let epttype = "host";
        let useStickySession =  $(editor).find(".UseStickySession")[0].checked;
        let DisableUptimeMonitor = !$(editor).find(".EnableUptimeMonitor")[0].checked;
        let disableAutoFallback = false; //$(editor).find(".DisableAutoFallback")[0].checked;
        let authProviderType = $(editor).find(".authProviderPicker input[type='radio']:checked").val();
        let requireRateLimit = $(editor).find(".RequireRateLimit")[0].checked;
        let rateLimit = $(editor).find(".RateLimit").val();
        let bypassGlobalTLS = $(editor).find(".BypassGlobalTLS")[0].checked;
        let disableChunkedTransferEncoding = $(editor).find(".DisableChunkedTransferEncoding")[0].checked;
        let disableLogging = $(editor).find(".DisableLogging")[0].checked;
        let disableStatisticCollection = $(editor).find(".DisableStatisticCollection")[0].checked;
        let blockCommonExploits = $(editor).find(".BlockCommonExploits")[0].checked;
        let blockAICrawlers = $(editor).find(".BlockAICrawlers")[0].checked;
        let mitigationAction = $(editor).find(".mitigationActionDropdown").dropdown("get value");
        let tags = getTagsArrayFromEndpoint(uuid);
        if (tags.length > 0){
            tags = tags.join(",");
        }else{
            tags = "";
        }

        cfgPayload = {
                "type": epttype,
                "rootname": uuid,
                "ss":useStickySession,
                "dutm": DisableUptimeMonitor,
                "dAutoFallback": disableAutoFallback,
                "bpgtls": bypassGlobalTLS,
                "authprovider" :authProviderType,
                "rate" :requireRateLimit,
                "dChunkedEnc": disableChunkedTransferEncoding,
                "dLogging": disableLogging,
                "dStatisticCollection": disableStatisticCollection,
                "blockCommonExploits": blockCommonExploits,
                "blockAICrawlers": blockAICrawlers,
                "mitigationAction": mitigationAction,
                "ratenum" :rateLimit,
                "tags": tags,
            };
        console.log("updating proxy config:", cfgPayload);

        $.cjax({
            url: "/api/proxy/edit",
            method: "POST",
            data: cfgPayload,
            success: function(data){
                if (data.error !== undefined){
                    msgbox(data.error, false, 6000);
                }else{
                    msgbox("Proxy endpoint updated");
                    listProxyEndpoints();
                }
            }
        })
    }

    //Generic functions for delete rp endpoints 
    function deleteEndpoint(epoint){
        epoint = decodeURIComponent(epoint).hexDecode();
        if (confirm("Confirm remove proxy for :" + epoint + "?")){
            $.cjax({
                url: "/api/proxy/del",
                method: "POST",
                data: {ep: epoint},
                success: function(data){
                    if (data.error == undefined){
                        listProxyEndpoints();
                        msgbox("Proxy Rule Deleted", true);
                        reloadUptimeList();
                    }else{
                        msgbox(data.error, false);
                    }
                }
            })
        }
    }

    
    /* button events */
    function editBasicAuthCredentials(uuid){
        let payload = encodeURIComponent(JSON.stringify({
            ept: "host",
            ep: uuid
        }));
        showEditorSideWrapper("snippet/basicAuthEditor.html?t=" + Date.now() + "#" + payload);
    }


    function quickEditVdir(uuid){
        openTabById("vdir");
        $("#vdirBaseRoutingRule").parent().dropdown("set selected", uuid);
    }

    //Open the load balance option
    function editUpstreams(uuid){
        let payload = encodeURIComponent(JSON.stringify({
            ept: "host",
            ep: uuid
        }));
        showEditorSideWrapper("snippet/upstreams.html?t=" + Date.now() + "#" + payload);
    }

    function handleProxyRuleToggle(object){
        let endpointUUID = $(object).attr("eptuuid");
        let isChecked = object.checked;
        $.cjax({
            url: "/api/proxy/toggle",
            data: {
                "ep": endpointUUID,
                "enable": isChecked
            },
            success: function(data){
                if (data.error != undefined){
                    msgbox(data.error, false);
                }else{
                    if (isChecked){
                        msgbox("Proxy Rule Enabled");
                    }else{
                        msgbox("Proxy Rule Disabled");
                    }
                    
                }
            }
        })
    }

    /* 
        Certificate Shortcut
    */

    function requestCertificateForExistingHost(hostUUID, RootAndAliasDomains, btn=undefined){
        RootAndAliasDomains = JSON.parse(decodeURIComponent(RootAndAliasDomains))
        let renewDomainKey = RootAndAliasDomains.join(",");
        let preferedACMEEmail = $("#prefACMEEmail").val();
        if (preferedACMEEmail == ""){
            msgbox("Preferred email for ACME registration not set", false);
            return;
        }
        let defaultCA = $("#defaultCA").dropdown("get value");
        if (defaultCA == ""){
            defaultCA = "Let's Encrypt";
        }

        //Check if the root or the alias domain contain wildcard character, if yes, return error
        for (var i = 0; i < RootAndAliasDomains.length; i++){
            if (RootAndAliasDomains[i].indexOf("*") != -1){
                msgbox("Wildcard domain can only be setup via ACME tool", false);
                return;
            }
        }
        
        //Renew the certificate
        renewCertificate(renewDomainKey, false, btn);
    }

    function generateSelfSignedCertificate(uuid, domains, btn=undefined){
        let payload = JSON.stringify(domains);
        $.cjax({
            url: "/api/cert/selfsign",
            data: {
                "cn": uuid,
                "domains": payload
            },
            success: function(data){
                if (data.error == undefined){
                    msgbox("Self-Signed Certificate Generated", true);
                    resyncProxyEditorConfig();
                    if (typeof(initManagedDomainCertificateList) != undefined){
                        //Re-init the managed domain certificate list
                        initManagedDomainCertificateList();
                    }
                }else{
                    msgbox(data.error, false);
                }
            }
        });
    }

    /* Tags & Search */
    function handleSearchInput(event){
        if (event.key == "Escape"){
            $("#searchInput").val("");
        }
        filterProxyList();
    }

     // Function to filter the proxy list
     function filterProxyList() {
        let searchInput = $("#searchInput").val().toLowerCase();
        let selectedTag = $("#tagFilterDropdown").dropdown('get value');
        $("#httpProxyList tr").each(function() {
            let host = $(this).find("td[data-label='']").text().toLowerCase();
            let tagElements = $(this).find("td[data-label='tags']");
            let tags = tagElements.attr("payload");
            tags = JSON.parse(decodeURIComponent(tags));
            if ((host.includes(searchInput) || searchInput === "") && (tags.includes(selectedTag) || selectedTag === "")) {
                $(this).show();
            } else {
                $(this).hide();
            }
        });
    }

    // Function to generate a color based on a tag name
    function getTagColorByName(tagName) {
        function hashCode(str) {
            return str.split('').reduce((prevHash, currVal) =>
                ((prevHash << 5) - prevHash) + currVal.charCodeAt(0), 0);
        }
        let hash = hashCode(tagName);
        let color = '#' + ((hash >> 24) & 0xFF).toString(16).padStart(2, '0') +
                            ((hash >> 16) & 0xFF).toString(16).padStart(2, '0') +
                            ((hash >> 8) & 0xFF).toString(16).padStart(2, '0');
        return color;
    }

    function getTagTextColor(tagName){
        let color = getTagColorByName(tagName);
        let r = parseInt(color.substr(1, 2), 16);
        let g = parseInt(color.substr(3, 2), 16);
        let b = parseInt(color.substr(5, 2), 16);
        let brightness = Math.round(((r * 299) + (g * 587) + (b * 114)) / 1000);
        return brightness > 125 ? "#000000" : "#ffffff";
    }
    
     // Populate the tag filter dropdown
     function populateTagFilterDropdown(data) {
        let tags = new Set();
        data.forEach(subd => {
            subd.Tags.forEach(tag => tags.add(tag));
        });
        tags = Array.from(tags).sort((a, b) => a.localeCompare(b));
        let dropdownMenu = $("#tagFilterDropdown .tagList");
        dropdownMenu.html(`<div class="item tag-select" data-value="">
            <div class="ui grey empty circular label"></div>
            Show all
        </div>`);
        tags.forEach(tag => {
            let thisTagColor = getTagColorByName(tag);
            dropdownMenu.append(`<div class="item tag-select" data-value="${tag}">
                <div class="ui empty circular label" style="background-color: ${thisTagColor}; border-color: ${thisTagColor};" ></div>
                ${tag}
            </div>`);
        });
    }

    // Edit tags for a specific endpoint
    function editTags(uuid){
        let payload = encodeURIComponent(JSON.stringify({
            ept: "host",
            ep: uuid
        }));
        showEditorSideWrapper("snippet/tagEditor.html?t=" + Date.now() + "#" + payload);
    }

    // Render the tags preview from tag editing snippet, callback from tags editor
    function renderTagsPreview(endpoint, tags){
        let targetProxyRuleEle = $(".subdEntry[eptuuid='" + endpoint + "'] td[data-label='tags']");
        //Update the tag DOM
        let newTagDOM = tags.map(tag => `<span class="ui tiny label tag-select" style="background-color: ${getTagColorByName(tag)}; color: ${getTagTextColor(tag)}">${tag}</span>`).join("");
        $(targetProxyRuleEle).find(".tags-list").html(newTagDOM);

        //Update the tag payload
        $(targetProxyRuleEle).attr("payload", encodeURIComponent(JSON.stringify(tags)));
    }


    function getTagsArrayFromEndpoint(endpoint){
        let subd = getEditingHttpProxyCachedSubd();
        return tags = subd.Tags || [];
    }
    
    /* Modal Events */
    $("#httprpEditDarkenLayer").on("click", function() {
        closeHttpRuleEditor();
    });

    function closeHttpRuleEditor(){
        // Fixing a bug in semantic ui that when an element fade in/out on top of checkbox
        // the checkbox suddently flash on top of the fading element
        $(".ui.toggle.tiny.fitted.checkbox").css("z-index", 0);
        $("#httprpEditModalWrapper").fadeOut("fast", function(){
            $(".ui.toggle.tiny.fitted.checkbox").css("z-index", "auto");
            $("body").css("overflow", "auto");
            exitProxyInlineEdit();
        }); 
    }

    //Get the current editing http hostname, return null if errors
    function getEditingHttpProxyHostname(){
        let hostname = $("#httprpEditModal").attr("editing-host");
        if (hostname == ""){
            return null;
        }
        return decodeURIComponent(hostname);
    }

    function getEditingHttpProxyCachedSubd(){
        let hostname = getEditingHttpProxyHostname();
        if (hostname == null){
            return null;
        }
        let subd = httpProxyList.find(subd => subd.RootOrMatchingDomain === hostname);
        return subd;
    }

    // Generate a certificate dropdown for the HTTP Proxy Rule Editor
    // so user can pick which certificate they want to use for the current editing hostname
    function generateCertificateDropdown(callback){
        $.ajax({
            url: "/api/cert/list",
            method: "GET",
            success: function(data) {
                let dropdown = $('<div class="ui fluid selection dropdown"></div>');
                let menu = $('<div class="menu"></div>');
                data.forEach(cert => {
                    menu.append(`<div class="item" data-value="${cert}">${cert}</div>`);
                });
                // Add a hidden input to store the selected certificate
                dropdown.append('<input type="hidden" name="certificate">');
                dropdown.append('<i class="dropdown icon"></i>');
                dropdown.append('<div class="default text">Fallback Certificate</div>');
                dropdown.append(menu);
                callback(dropdown);
            }
        })
    }

    //Initialize the http proxy rule editor
    function initHttpProxyRuleEditorModal(rulepayload){
        let subd = JSON.parse(JSON.stringify(rulepayload));
    
        //Populate all the information in the proxy editor
        populateAndBindEventsToHTTPProxyEditor(subd);

        //Hide all previously opened editor side-frame wrapper
        hideEditorSideWrapper();

        //Show the first rpconfig
        $("#httprpEditModal .rpconfig_content").hide();
        $("#httprpEditModal .rpconfig_content[rpcfg='downstream']").show();
        $("#httprpEditModal .hrpedit_menu_item.active").removeClass("active");
        $("#httprpEditModal .hrpedit_menu_item[cfgpage='downstream']").addClass("active");
        $("body").css("overflow", "hidden");
        // Fixing a bug in semantic ui that when an element fade in/out on top of checkbox
        // the checkbox suddently flash on top of the fading element
        $(".ui.toggle.tiny.fitted.checkbox").css("z-index", 0);
        $("#httprpEditModalWrapper").fadeIn("fast", function(){
            $(".ui.toggle.tiny.fitted.checkbox").css("z-index", "auto");
        });
    }

    // This function populate the bind all the events required for the proxy editor
    // pass a copy of the data structure of subd to prevent modification to the original one
    function populateAndBindEventsToHTTPProxyEditor(subd){
        //Assign the editing host to DOM element
        let uuid = subd.RootOrMatchingDomain; //Each matching hostname as uuid
        $("#httprpEditModal").attr("editing-host", encodeURIComponent(uuid));

        /* ------------ Downstream ------------ */
        let editor = $("#httprpEditModalWrapper");
        
        //Check if the domain is wildcard domain, if yes do not render as a link
        if (subd.RootOrMatchingDomain.indexOf("*") > -1){
            editor.find(".downstream_primary_hostname").html(subd.RootOrMatchingDomain);
        }else{
            editor.find(".downstream_primary_hostname").html(`<a href="//${subd.RootOrMatchingDomain}" target="_blank">${subd.RootOrMatchingDomain}</a>`);
        }
        editor.find(".BypassGlobalTLS").off('change');
        editor.find(".BypassGlobalTLS").prop("checked", subd.BypassGlobalTLS);
        editor.find(".BypassGlobalTLS").on("change", function() {
            saveProxyInlineEdit(uuid);
        });

        editor.find(".DisableLogging").off('change');
        editor.find(".DisableLogging").prop("checked", subd.DisableLogging);
        editor.find(".DisableLogging").on("change", function() {
            // When logging is disabled, also disable statistic collection
            if ($(this).is(':checked')) {
                editor.find(".DisableStatisticCollection").prop("checked", true).prop("disabled", true);
            } else {
                editor.find(".DisableStatisticCollection").prop("disabled", false);
            }
            saveProxyInlineEdit(uuid);
        });

        editor.find(".DisableStatisticCollection").off('change');
        editor.find(".DisableStatisticCollection").prop("checked", subd.DisableStatisticCollection);
        editor.find(".DisableStatisticCollection").on("change", function() {
            saveProxyInlineEdit(uuid);
        });

        // Handle initial state: if logging is disabled, disable statistic collection
        if (subd.DisableLogging) {
            editor.find(".DisableStatisticCollection").prop("checked", true).prop("disabled", true);
        }

        // Exploit Detection
        editor.find(".BlockCommonExploits").off('change');
        editor.find(".BlockCommonExploits").prop("checked", subd.BlockCommonExploits || false);
        editor.find(".BlockCommonExploits").on("change", function() {
            saveProxyInlineEdit(uuid);
        });

        editor.find(".BlockAICrawlers").off('change');
        editor.find(".BlockAICrawlers").prop("checked", subd.BlockAICrawlers || false);
        editor.find(".BlockAICrawlers").on("change", function() {
            saveProxyInlineEdit(uuid);
        });

        editor.find(".mitigationActionDropdown").off('change');
        editor.find(".mitigationActionDropdown input[type='hidden']").val((subd.MitigationAction || 0).toString());
        setTimeout(function(){
              editor.find(".mitigationActionDropdown").dropdown({
                onChange: function(value) {
                    saveProxyInlineEdit(uuid);
                }
            });
        }, 100);
      
        
        //Bind the edit button
        editor.find(".downstream_primary_hostname_edit_btn").off("click").on("click", function(){
            editor.find(".downstream_primary_hostname_edit_btn").parent().hide();
            editor.find(".downstream_primary_hostname_edit_input input").val(subd.RootOrMatchingDomain)
            editor.find(".downstream_primary_hostname_edit_input").show();
        });
        editor.find(".cancelDownstreamHostnameBtn").off("click").on("click", function(){
            editor.find(".downstream_primary_hostname_edit_input").hide();
            editor.find(".downstream_primary_hostname_edit_btn").parent().show();
        });
        editor.find(".saveDownstreamHostnameBtn").off("click").on("click", function(){
            let newHostname = editor.find(".downstream_primary_hostname_edit_input input").val().trim();
            if (newHostname.length == 0){
                msgbox("Hostname cannot be empty", false);
                return;
            }

            if (newHostname == subd.RootOrMatchingDomain){
                //No need to update
                editor.find(".downstream_primary_hostname_edit_input").hide();
                editor.find(".downstream_primary_hostname_edit_btn").parent().show();
                return;
            }
            $.cjax({
                url: "/api/proxy/setHostname",
                method: "POST",
                data: {
                    "oldHostname":subd.RootOrMatchingDomain,
                    "newHostname":newHostname,
                },
                success: function(data){
                    if (data.error != undefined){
                        msgbox(data.error, false);
                    }else{
                        //Update the current editing hostname to DOM
                        $("#httprpEditModal").attr("editing-host", encodeURIComponent(newHostname));
                        //Grab the new hostname from server
                        resyncProxyEditorConfig();
                    }
                }
            });
        });
        editor.find(".downstream_primary_hostname_edit_input").hide();
        editor.find(".downstream_primary_hostname_edit_btn").parent().show();
        
        //Build the alias hostname list
        let aliasHTML = "";
        subd.MatchingDomainAlias.forEach(alias => {
            if (alias.indexOf("*") > -1){
                //Wildcard alias
                aliasHTML += `<span class="ui tiny label">${alias}</span> `;
            }else{
                //Normal alias
                aliasHTML += `<span class="ui tiny label"><a href="//${alias}" target="_blank">${alias}</a></span> `;
            }
            
        });
        editor.find(".downstream_alias_hostname").html(aliasHTML);

        /* ------------ Upstreams ------------ */
        editor.find(".upstream_list").html(renderUpstreamList(subd));
        editor.find(".editUpstreamButton").off("click").on("click", function(){
            editUpstreams(uuid);
        });

        editor.find(".EnableUptimeMonitor").off("change");
        editor.find(".EnableUptimeMonitor").prop("checked", !subd.DisableUptimeMonitor);
        editor.find(".EnableUptimeMonitor").on("change", function() {
            // Enable/disable the auto fallback option based on uptime monitor state
            var isUptimeMonitorEnabled = $(this).is(":checked");
            editor.find(".DisableAutoFallback").prop("disabled", !isUptimeMonitorEnabled);
            if (!isUptimeMonitorEnabled) {
                editor.find(".DisableAutoFallback").prop("checked", false);
            }
            saveProxyInlineEdit(uuid);
        });

        editor.find(".DisableAutoFallback").off("change");
        editor.find(".DisableAutoFallback").prop("checked", subd.DisableAutoFallback);
        editor.find(".DisableAutoFallback").prop("disabled", subd.DisableUptimeMonitor);
        editor.find(".DisableAutoFallback").on("change", function() {
            saveProxyInlineEdit(uuid);
        });

        editor.find(".UseStickySession").off("change");
        editor.find(".UseStickySession").prop("checked", subd.UseStickySession);
        editor.find(".UseStickySession").on("change", function() {
            saveProxyInlineEdit(uuid);
        });

        editor.find(".DisableChunkedTransferEncoding").off("change");
        editor.find(".DisableChunkedTransferEncoding").prop("checked", subd.DisableChunkedTransferEncoding);
        editor.find(".DisableChunkedTransferEncoding").on("change", function() {
            saveProxyInlineEdit(uuid);
        });

        /* ------------ Vdirs ------------ */
        editor.find(".vdir_list").html(renderVirtualDirectoryList(subd));
        editor.find(".editVdirBtn").off("click").on("click", function(){
            quickEditVdir(uuid);
            //Temporary restore scroll
            $("body").css("overflow", "auto");
        });

        /* ------------ Alias ------------ */ 
        (() => {
            let payload = encodeURIComponent(JSON.stringify({
                ept: "host",
                ep: uuid
            }));
            let frameURL = "snippet/aliasEditor.html?t=" + Date.now() + "#" + payload;
            editor.find(".rpconfig_content[rpcfg='alias'] .wrapper_frame").attr('src', frameURL);
        })();

        /* ------------ Headers ------------ */ 
        (() => {
            let payload = encodeURIComponent(JSON.stringify({
                ept: "host",
                ep: uuid
            }));
            let frameURL = "snippet/customHeaders.html?t=" + Date.now() + "#" + payload;
            editor.find(".rpconfig_content[rpcfg='headers'] .wrapper_frame").attr('src', frameURL);
        })();

        /* ------------ Access Rule ------------ */
        (()=>{
            let payload = encodeURIComponent(JSON.stringify({
                ept: "host",
                ep: uuid
            }));
            let frameURL = "snippet/hostAccessEditor.html?t=" + Date.now() + "#" + payload;
            editor.find(".rpconfig_content[rpcfg='accessrule'] .wrapper_frame").attr('src', frameURL);
        })();

        /* ------------ Security ------------ */
    
        let authMethodContent = "";
        switch (subd.AuthenticationProvider.AuthMethod) {
        case 0x1:
            editor.find(".authProviderPicker input[value='1']").prop("checked", true);
            break;
        case 0x2:
            editor.find(".authProviderPicker input[value='2']").prop("checked", true);
            break;
        case 0x3:
            editor.find(".authProviderPicker input[value='3']").prop("checked", true);
            break;
        default:
            editor.find(".authProviderPicker input[value='0']").prop("checked", true);
            break;
        }

        editor.find(".authProviderPicker input[type='radio']").off("change").on("change", function() {
            saveProxyInlineEdit(uuid);
        });

        editor.find(".editBasicAuthCredentialsBtn").off("click").on("click", function(){
            editBasicAuthCredentials(uuid);
        });

        //Rate limit
        if (subd.RequireRateLimit) {
            editor.find(".RequireRateLimit").prop("checked", true);
            editor.find(".RateLimit").parent().removeClass("disabled");
        } else {
            editor.find(".RequireRateLimit").prop("checked", false);
            editor.find(".RateLimit").parent().addClass("disabled");
        }

        function rateLimitChangeEvent(){
            let rateLimitValue = $(this).val();
            if (rateLimitValue < 0 || isNaN(rateLimitValue)) {
                msgbox("Rate limit must be >= 0", false);
                $(this).val(subd.RateLimit); // Reset to previous valid value
                return;
            }
            saveProxyInlineEdit(uuid);
        }

        editor.find(".RequireRateLimit").off("change").on("change", function() {
            if ($(this).is(":checked")) {
                editor.find(".RateLimit").parent().removeClass("disabled");
            } else {
                editor.find(".RateLimit").parent().addClass("disabled");
            }

            if (subd.RateLimit === 0) {
                subd.RateLimit = 100; // Set default rate limit to 100 if uninitialized
                $(this).val(subd.RateLimit);
                editor.find(".RateLimit").off("change"); // Temporarily disable the change event handler
                editor.find(".RateLimit").val(100); // Set the value to 100
                editor.find(".RateLimit").on("change", rateLimitChangeEvent); // Re-enable the change event handler
            }
            saveProxyInlineEdit(uuid);
        });
        editor.find(".RateLimit").attr("value", subd.RateLimit);
        editor.find(".RateLimit").off("change").on("change", rateLimitChangeEvent);

        /* ------------ TLS ------------ */
        updateTlsResolveList(uuid);
        if (subd.TlsOptions){
            editor.find(".Tls_EnableSNI").prop("checked", !subd.TlsOptions.DisableSNI);
            editor.find(".Tls_EnableLegacyCertificateMatching").prop("checked", !subd.TlsOptions.DisableLegacyCertificateMatching);
            editor.find(".Tls_EnableAutoHTTPS").prop("checked", !!subd.TlsOptions.EnableAutoHTTPS);
        }else{
            //Use default options
            editor.find(".Tls_EnableSNI").prop("checked", true);
            editor.find(".Tls_EnableLegacyCertificateMatching").prop("checked", true);
            editor.find(".Tls_EnableAutoHTTPS").prop("checked", false);
        }
      
        editor.find(".Tls_EnableSNI").off("change").on("change", function() {
            saveTlsConfigs(uuid);
        });
        editor.find(".Tls_EnableLegacyCertificateMatching").off("change").on("change", function() {
            saveTlsConfigs(uuid);
        });
        editor.find(".Tls_EnableAutoHTTPS").off("change").on("change", function() {
            saveTlsConfigs(uuid);
        });

        /* Quick access to get certificate for the current host */
        let enableQuickRequestButton = true;
        let domains = [subd.RootOrMatchingDomain]; //Domain for getting certificate if needed
        for (var i = 0; i < subd.MatchingDomainAlias.length; i++){
            let thisAliasName = subd.MatchingDomainAlias[i];
            domains.push(thisAliasName);
        }

        //Check if the domain or alias contains wildcard, if yes, disabled the get certificate button
        if (subd.RootOrMatchingDomain.indexOf("*") > -1){
            enableQuickRequestButton = false;
        }
        
        if (subd.MatchingDomainAlias != undefined){
            for (var i = 0; i < subd.MatchingDomainAlias.length; i++){
                if (subd.MatchingDomainAlias[i].indexOf("*") > -1){
                    enableQuickRequestButton = false;
                    break;
                }
            }
        }
        if (enableQuickRequestButton){
            editor.find(".getCertificateBtn").removeClass("disabled");
        }else{
            editor.find(".getCertificateBtn").addClass("disabled");
        }

        editor.find(".getCertificateBtn").off("click").on("click", function(){
            let certificateDomains = encodeURIComponent(JSON.stringify(domains));
            requestCertificateForExistingHost(uuid, certificateDomains, this);
        });

        // Bind event to self-signed certificate button
        editor.find(".getSelfSignCertBtn").off("click").on("click", function() {
            generateSelfSignedCertificate(uuid, domains, this);
        });

       

        /* ------------ Tags ------------ */
        (()=>{
            let payload = encodeURIComponent(JSON.stringify({
                ept: "host",
                ep: uuid
            }));
            let frameURL = "snippet/tagEditor.html?t=" + Date.now() + "#" + payload;
            editor.find(".rpconfig_content[rpcfg='tags'] .wrapper_frame").attr('src', frameURL);
        })();

        console.log(subd);
    }

    // Pull the latest proxy config from server side again and populate the editor
    // with latest settings
    function resyncProxyEditorConfig(){
        let currentEditingHostname = getEditingHttpProxyHostname();
        $.get("/api/proxy/list?type=host", function(data){
            data.sort((a,b) => (a.RootOrMatchingDomain > b.RootOrMatchingDomain) ? 1 : ((b.RootOrMatchingDomain > a.RootOrMatchingDomain) ? -1 : 0));
            let editingHost = data.find(subd => subd.RootOrMatchingDomain === currentEditingHostname);
            if (editingHost) {
                populateAndBindEventsToHTTPProxyEditor(editingHost);
            } else {
                closeHttpRuleEditor();
            }
        });
    }

    //bind events to hrpedit_menu_item
    $(".hrpedit_menu_item").on("click", function() {
        $(".hrpedit_menu_item.active").removeClass("active");
        $(this).addClass("active");
        let cfgPageId = $(this).attr("cfgpage");
        $("#httprpEditModal .rpconfig_content").hide();
        $(`#httprpEditModal .rpconfig_content[rpcfg='${cfgPageId}']`).show();
        $("#httprpEditModal .wrapper_frame").contents().scrollTop(0);
        hideEditorSideWrapper(); //Always close the side wrapper on tab change
    });

    $("#httprpEditModal .editor_back_button").on("click", function(event) {
        // Prevent click event from propagating to the modal background
        event.stopPropagation();
        hideEditorSideWrapperViaBtn();
    });

    function showEditorSideWrapper(url){
        $("#httprpEditModal .editor_side_wrapper .wrapper_frame").attr('src', url);
        $("#httprpEditModal .editor_side_wrapper").fadeIn("fast");
    }

    function hideEditorSideWrapperViaBtn(){
        hideEditorSideWrapper();
        resyncProxyEditorConfig();
    }

    function hideEditorSideWrapper(){
        $("#httprpEditModal .editor_side_wrapper").fadeOut("fast", function(){
            // Reset the side wrapper frame URL to prevent stale content
            $("#httprpEditModal .editor_side_wrapper .wrapper_frame").attr('src', 'snippet/placeholder.html');
        });
    }

    /*
        Page Initialization Functions 
    */

    // Initialize the proxy list on page load
    $(document).ready(function() {
        listProxyEndpoints();

        // Event listener for clicking on tags
        $(document).on('click', '.tag-select', function() {
            let tag = $(this).text().trim();
            $('#tagFilterDropdown').dropdown('set selected', tag);
            filterProxyList();
        });
    });

    //Bind on tab switch events
    tabSwitchEventBind["httprp"] = function(){
        //Check if the proxy editor is opened
        if ($("#httprpEditModalWrapper").is(":visible")) {
            // When page switch from Vdir and back to this page
            // there is a chance where the user has modified the Vdir
            // we need to get the latest setting from server side and 
            // render it again
            resyncProxyEditorConfig();
            window.scrollTo(0, 0);
            $("body").css("overflow", "hidden");
        } else {
            listProxyEndpoints();
            //Reset the tag filter
            $("#tagFilterDropdown").dropdown('set selected', "");
        }
    }
        
</script>
